﻿using System;
using System.Collections.Generic;
using System.ComponentModel;

using Inspire.Interfaces;
using System.Collections;

namespace Inspire.Entities
{
    public partial class Person : IDataErrorInfo, IValidation
    {
        #region IDataErrorInfo Implementation
        
        /// <summary>
        /// Stores message messages mapped to the name of the property to which they belong.
        /// </summary>
        protected Dictionary<string, string> _errors = new Dictionary<string, string>();
        
        /// <summary>
        /// General Error message regarding this object.
        /// 
        /// This is part of the IDataErrorInfo implementation.
        /// </summary>
        public string Error
        {
            get
            {
                return String.Empty;
            }
        }

        /// <summary>
        /// Indexer for properties of this object.
        /// 
        /// This is part of the IDataErrorInfo implementation.
        /// </summary>
        /// <param name="columnName">(string) The property to check for errors.</param>
        /// <returns>(string) If an there is an message with the specified property, the message message for that message.</returns>
        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                {
                    return _errors[columnName];
                }
                return String.Empty;
            }
        }

        #endregion

        #region Partial Implementation of Property Event Handlers

        /// <summary>
        /// Event handler for changing of the Address1 property.
        /// </summary>
        /// <param name="value">(string) The new value of the Address1 property.</param>
        partial void OnAddress1Changing(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateAddress1(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("Address1")))
                {
                    this._errors.Add("Address1", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("Address1");
            }
        }

        /// <summary>
        /// Event handler for changing of the Address2 property.
        /// </summary>
        /// <param name="value">(string) The new value of the Address2 property.</param>
        partial void OnAddress2Changing(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateAddress2(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("Address2")))
                {
                    this._errors.Add("Address2", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("Address2");
            }
        }

        /// <summary>
        /// Event handler for changing of the City property.
        /// </summary>
        /// <param name="value">(string) The new value of the City property.</param>
        partial void OnCityChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateCity(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("City")))
                {
                    this._errors.Add("City", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("City");
            }
        }

        /// <summary>
        /// Event handler for changing of the Country property
        /// </summary>
        /// <param name="value">(string) The new value of the Country property.</param>
        partial void OnCountryChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = ValidateCountry(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("Country")))
                {
                    this._errors.Add("Country", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("Country");
            }
        }

        /// <summary>
        /// Event handler for changing of the FirstName property.
        /// </summary>
        /// <param name="value">(string) The new value of the FirstName property.</param>
        partial void OnFirstNameChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateFirstName(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("FirstName")))
                {
                    this._errors.Add("FirstName", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("FirstName");
            }
        }

        /// <summary>
        /// Event handler for changing of the LastName property.
        /// </summary>
        /// <param name="value">(string) The new value of the LastName property.</param>
        partial void OnLastNameChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateLastName(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("LastName")))
                {
                    this._errors.Add("LastName", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("LastName");
            }
        }

        /// <summary>
        /// Event handler for changing of the MiddleName property.
        /// </summary>
        /// <param name="value">(string) The new value of the MiddleName property.</param>
        partial void OnMiddleNameChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateMiddleName(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("MiddleName")))
                {
                    this._errors.Add("MiddleName", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("MiddleName");
            }
        }

        /// <summary>
        /// Event handler for changing of the PostalCode property
        /// </summary>
        /// <param name="value">(string) The new value of the PostalCode property.</param>
        partial void OnPostalCodeChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidatePostalCode(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("PostalCode")))
                {
                    this._errors.Add("PostalCode", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("PostalCode");
            }
        }        
        
        /// <summary>
        /// Event handler for changing of the State property.
        /// </summary>
        /// <param name="value">(string) The new value of the State property.</param>
        partial void OnStateChanging(string value)
        {
            // Get a Validation Message if it fails validation
            string errorMessage = this.ValidateCity(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("State")))
                {
                    this._errors.Add("State", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("State");
            }
        }
        
        #endregion

        #region IValidation Members

        /// <summary>
        /// Return a validation message for Address1
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateAddress1(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "Address 1 cannot be blank.";
            }
            if (value.Length > 100)
            {
                return "Address 1 has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for Address2
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateAddress2(string value)
        {
            if (value != null && value.Length > 100)
            {
                return "Address 2 has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for City
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateCity(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "City cannot be blank.";
            }
            if (value.Length > 100)
            {
                return "City has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for Comments
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateComments(string value)
        {
            if (value != null && value.Length > 2000)
            {
                return "Comments has a max length of 2000 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for Country
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateCountry(string value)
        {
            if (value != null && value.Length > 100)
            {
                return "Country has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for First Name
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateFirstName(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "First Name cannot be blank.";
            }
            if (value.Length > 100)
            {
                return "First Name has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for Last Name
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateLastName(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "Last Name cannot be blank.";
            }
            if (value.Length > 100)
            {
                return "Last Name has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validate message for Middle Name
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateMiddleName(string value)
        {
            if (value != null && value.Length > 100)
            {
                return "Middle Name has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for PostalCode
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidatePostalCode(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "Postal Code cannot be blank.";
            }
            if (value.Length > 100)
            {
                return "Postal Code has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Return a validation message for State
        /// </summary>
        /// <param name="value">The value to be validated</param>
        /// <returns>(string) Error message</returns>
        protected string ValidateState(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "State cannot be blank.";
            }
            if(value.Length > 100)
            {
                return "State has a max length of 100 characters";
            }
            return String.Empty;
        }
        
        /// <summary>
        /// Validate all fields
        /// </summary>
        /// <returns>bool True if no errors were found; false, otherwise.</returns>
        public virtual bool Validate()
        {
            // Initialize isValidated to True
            bool isValidated = true;

            // Clear all message messages
            this._errors.Clear();

            // Store message for Validation
            string message;

            #region Validate fields and add message messages to _errors
            
            // First Name
            message = ValidateFirstName(this.FirstName);
            if (message.Length > 0)
            {
                this._errors.Add("FirstName", message);
                isValidated = false;
            }

            // Middle Name
            message = ValidateMiddleName(this.MiddleName);
            if (message.Length > 0)
            {
                this._errors.Add("MiddleName", message);
                isValidated = false;
            }

            // Last Name
            message = ValidateLastName(this.LastName);
            if (message.Length > 0)
            {
                this._errors.Add("LastName", message);
                isValidated = false;
            }

            // Address1
            message = ValidateAddress1(this.Address1);
            if (message.Length > 0)
            {
                this._errors.Add("Address1", message);
                isValidated = false;
            }

            // Address2
            message = ValidateAddress2(this.Address2);
            if (message.Length > 0)
            {
                this._errors.Add("Address2", message);
                isValidated = false;
            }

            // City
            message = ValidateCity(this.City);
            if (message.Length > 0)
            {
                this._errors.Add("City", message);
                isValidated = false;
            }

            // State
            message = ValidateState(this.State);
            if (message.Length > 0)
            {
                this._errors.Add("State", message);
                isValidated = false;
            }

            // PostalCode
            message = ValidatePostalCode(this.PostalCode);
            if (message.Length > 0)
            {
                this._errors.Add("PostalCode", message);
                isValidated = false;
            }

            #endregion

            return isValidated;
        }

        /// <summary>
        /// Get all the errors found after the Validate() method is ran
        /// </summary>
        /// <returns>string[] of all message messages</returns>
        public string[] GetAllErrors()
        {
            string[] allErrors = new string[this._errors.Count];

            int counter = 0;
            foreach (KeyValuePair<string, string> nextError in this._errors)
            {
                allErrors[counter] = nextError.Value;
                counter++;
            }

            return allErrors;
        }

        #endregion

        /// <summary>
        /// Provides a Shallow Copy of this object.
        /// </summary>
        /// <returns>(Person) A Shallow Copy of the original Person object.</returns>
        public Person ShallowCopy()
        {
            return (Person)this.MemberwiseClone();
        }

        /// <summary>
        /// Resets all values to their default except the Circulations property. This method does not commit the changes to the database.
        /// </summary>
        public void Reset()
        {
            // Clear Error Messages of the fields in case setting a field to "" causes an message message to be added.
            // If an message message for the field already exists, this will cause a duplicate key message.
            this._errors.Clear();

            // Clear All Fields
            this.Address1 = "";
            this.Address2 = "";                
            this.City = "";
            this.Country = "";
            this.FirstName = "";
            this.LastName = "";
            this.MiddleName = "";
            this.Notes = "";
            this.PostalCode = "";
            this.State = "";

            // Clear Error Messages Regarding the Empty Fields
            this._errors.Clear();
        }
    }
}